﻿Imports System.IO
Imports Runa.Core.ResourceManager
Imports System.IO.IsolatedStorage
Imports ICSharpCode.SharpZipLib
Imports ICSharpCode.SharpZipLib.Zip

#If WINDOWS_PHONE Then
Imports System.Windows.Controls
Imports System.Windows.Media
Imports System.Windows.Media.Imaging
#ElseIf WINDOWS Then
Imports System.Drawing
#End If

Public Class GameParser
    Implements IDisposable

    Public Property Name() As String
    Public Property Author() As String
    Public Property WindowHeight() As Integer
    Public Property WindowWidth() As Integer
    Public Property Orientation() As String
    Public Property Fps() As Integer = 333333

#If WINDOWS_PHONE Then
    Public Property Image() As BitmapImage
#ElseIf WINDOWS Then
    Public Property Image() As System.Drawing.Bitmap
#End If

    Public Property LoadProgress() As Integer = 0
    Public Property SpriteBatchs() As New Dictionary(Of String, SpriteBatch)
    Public Property Fonts() As New Dictionary(Of String, FontObject)
    Public Property Textures() As New Dictionary(Of String, Texture2DObject)
    Public Property Audios() As New Dictionary(Of String, AudioObject)
    Public Property GameContentRoot() As String

    Public Property GlobalStatus() As New Dictionary(Of String, Object)

    Private m_imageStream As Stream

#If WINDOWS_PHONE Then
    Private m_fileStorage As IsolatedStorageFile = IsolatedStorageFile.GetUserStoreForApplication()
#ElseIf WINDOWS Then
    Private m_fileStorage As IsolatedStorageFile = IsolatedStorageFile.GetUserStoreForAssembly()
#End If

    Public Sub New(Optional ByVal fs As IsolatedStorageFile = Nothing)
        Me.Name = ""
        Me.Author = ""
        Me.m_fileStorage = If(fs, Me.m_fileStorage)
    End Sub

    Public Sub New(ByVal gameName As String, Optional ByVal f As IsolatedStorageFile = Nothing)
        Me.m_fileStorage = If(f, Me.m_fileStorage)
        If m_fileStorage.FileExists(gameName) Then
            Me.GameContentRoot = IO.Path.GetFileNameWithoutExtension(gameName)
            While True
                If m_fileStorage.DirectoryExists(Me.GameContentRoot) Then
                    Using fs As New IsolatedStorageFileStream(IO.Path.Combine(Me.GameContentRoot, "Configuration.xml"), FileMode.OpenOrCreate, m_fileStorage)
                        Dim configXml = XElement.Load(fs)
                        For Each element In configXml.Elements()
                            Select Case element.Name
                                Case "Name"
                                    Me.Name = element.Value
                                Case "Author"
                                    Me.Author = element.Value
                                Case "WindowHeight"
                                    Me.WindowHeight = CInt(element.Value)
                                Case "WindowWidth"
                                    Me.WindowWidth = CInt(element.Value)
                                Case "Orientation"
                                    Me.Orientation = element.Value
                                Case "Fps"
                                    Me.Fps = CInt(element.Value)
                                Case "Image"
#If WINDOWS_PHONE Then
                                    Me.Image = New BitmapImage()
                                    Me.m_imageStream = m_fileStorage.OpenFile(IO.Path.Combine(Me.GameContentRoot, element.Value), FileMode.Open)
                                    Me.Image.SetSource(Me.m_imageStream)
#ElseIf WINDOWS Then
                                    Me.m_imageStream = m_fileStorage.OpenFile(IO.Path.Combine(Me.GameContentRoot, element.Value), FileMode.Open)
                                    Me.Image = New Bitmap(Me.m_imageStream)
#End If
                                Case Else
                                    Continue For
                            End Select
                        Next
                        fs.Close()
                    End Using
                    Exit While
                Else
                    Me.ExtractGamePackage(gameName)
                    Continue While
                End If
            End While
        Else
            Throw New IO.FileNotFoundException(String.Format("File {0} not found.", gameName))
        End If
    End Sub

    Public Sub SaveFromLoadedResource(ByVal resourceName As String, ByVal globalName As String)
        Try
            If Me.Textures.ContainsKey(resourceName) Then
                If Me.GlobalStatus.ContainsKey(globalName) Then
                    Me.GlobalStatus(globalName) = Me.Textures(resourceName)
                Else
                    Me.GlobalStatus.Add(globalName, Me.Textures(resourceName))
                End If
            ElseIf Me.Fonts.ContainsKey(resourceName) Then
                If Me.GlobalStatus.ContainsKey(globalName) Then
                    Me.GlobalStatus(globalName) = Me.Fonts(resourceName)
                Else
                    Me.GlobalStatus.Add(globalName, Me.Fonts(resourceName))
                End If
            ElseIf Me.Audios.ContainsKey(resourceName) Then
                If Me.GlobalStatus.ContainsKey(globalName) Then
                    Me.GlobalStatus(globalName) = Me.Audios(resourceName)
                Else
                    Me.GlobalStatus.Add(globalName, Me.Audios(resourceName))
                End If
            Else
                Throw New ArgumentOutOfRangeException("The given key is not found in the loaded resources.")
            End If
        Catch ex As Exception
            Throw ex
        End Try
    End Sub

    Public Sub SaveByValue(ByVal globalName As String, ByVal obj As Object)
        Try
            Me.GlobalStatus.Add(globalName, obj)
        Catch ex As Exception
            Throw ex
        End Try
    End Sub

    Public Sub SaveObject(Of T)(ByVal globalName As String, ByVal obj As T)
        Try
            Me.GlobalStatus.Add(globalName, obj)
        Catch ex As Exception
            Throw ex
        End Try
    End Sub

    Public Function GetGlobalVariant(Of T)(ByVal vn As String) As T
        Return CType(Me.GlobalStatus(vn), T)
    End Function

    Private Function ExtractGamePackage(ByVal strPackageName As String) As Boolean
        Try
            If m_fileStorage.DirectoryExists(Me.GameContentRoot) Then
                m_fileStorage.DeleteDirectory(Me.GameContentRoot)
            End If
            m_fileStorage.CreateDirectory(Me.GameContentRoot)

            Using fs As New IsolatedStorageFileStream(strPackageName, FileMode.OpenOrCreate, m_fileStorage)
                Using zipStream As New ZipInputStream(fs)
                    Using reader = New BinaryReader(zipStream)
                        Dim theEntry As ZipEntry = Nothing
                        While (Function()
                                   theEntry = zipStream.GetNextEntry()
                                   Return theEntry IsNot Nothing
                               End Function)()
                            Dim fileName = theEntry.Name
                            If fileName <> String.Empty Then
                                If (Not theEntry.IsFile) Or _
                                    (Not theEntry.IsCompressionMethodSupported()) Or _
                                    (Not theEntry.CanDecompress) Then Continue While
                                Using isolatedFileStream As New IsolatedStorageFileStream(Me.GameContentRoot & "\" & fileName, FileMode.OpenOrCreate, FileAccess.ReadWrite, m_fileStorage)
                                    Using writer = New BinaryWriter(isolatedFileStream)
                                        Dim size = 2048
                                        Dim data(2048) As Byte
                                        While True
                                            size = reader.Read(data, 0, data.Length)
                                            If size > 0 Then
                                                writer.Write(data, 0, size)
                                            Else
                                                Exit While
                                            End If
                                        End While
                                        writer.Close()
                                    End Using
                                    isolatedFileStream.Close()
                                End Using
                            End If
                        End While
                        reader.Close()
                    End Using
                    zipStream.Close()
                End Using
                fs.Close()
            End Using
            Return True
        Catch ex As Exception
            Throw ex
            Return False
        End Try
    End Function

#Region "IDisposable Support"
    Private disposedValue As Boolean ' To detect redundant calls

    ' IDisposable
    Protected Overridable Sub Dispose(disposing As Boolean)
        If Not Me.disposedValue Then
            If disposing Then
                ' TODO: dispose managed state (managed objects).
            End If
            ' TODO: free unmanaged resources (unmanaged objects) and override Finalize() below.
            ' TODO: set large fields to null.
            Me.m_imageStream.Close()
        End If
        Me.disposedValue = True
    End Sub

    ' TODO: override Finalize() only if Dispose(ByVal disposing As Boolean) above has code to free unmanaged resources.
    'Protected Overrides Sub Finalize()
    '    ' Do not change this code.  Put cleanup code in Dispose(ByVal disposing As Boolean) above.
    '    Dispose(False)
    '    MyBase.Finalize()
    'End Sub

    ' This code added by Visual Basic to correctly implement the disposable pattern.
    Public Sub Dispose() Implements IDisposable.Dispose
        ' Do not change this code.  Put cleanup code in Dispose(disposing As Boolean) above.
        Dispose(True)
        GC.SuppressFinalize(Me)
    End Sub
#End Region

End Class